#include "windows.h"

#include "World.h"
#include "Town.h"
#include "Character.h"
#include "NPC.h"
#include "Window.h"

#include <string>
#include <iostream>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <memory>
#include <exception>

#include <btBulletDynamicsCommon.h>

/*
 * opens a debugg console
 */
void showWin32Console()
{
    static const WORD MAX_CONSOLE_LINES = 500;
    int hConHandle;
    long lStdHandle;
    CONSOLE_SCREEN_BUFFER_INFO coninfo;
    FILE *fp;
    // allocate a console for this app
    AllocConsole();
    // set the screen buffer to be big enough to let us scroll text
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
    coninfo.dwSize.Y = MAX_CONSOLE_LINES;
    SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),
    coninfo.dwSize);
    // redirect unbuffered STDOUT to the console
    lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "w" );
    *stdout = *fp;
    setvbuf( stdout, NULL, _IONBF, 0 );
    // redirect unbuffered STDIN to the console
    lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "r" );
    *stdin = *fp;
    setvbuf( stdin, NULL, _IONBF, 0 );
    // redirect unbuffered STDERR to the console
    lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "w" );
    *stderr = *fp;
    setvbuf( stderr, NULL, _IONBF, 0 );
    // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
    // point to console as well
    std::ios::sync_with_stdio();
}

/*
 * Entry point
 */
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
{
	/*
	 * load the world
	 */
	World midEarth(std::string("Mid Earth"));

	Town hobbit(0.9, 0.9, std::string("Hobbit"));
	midEarth.addScene(hobbit);
	midEarth.selectScene(hobbit);

	Character frodo(0.5f, 0.5f, 1.0f, std::string("Frodo"));
	hobbit.addEntity(frodo);

	NPC sam(-0.5f, -0.5f, 2.0f, std::string("Sam"));
	hobbit.addEntity(sam);

	NPC pippin(-0.2f, -0.2f, 3.0f, std::string("Pippin"));
	hobbit.addEntity(pippin);

	/*
	 * load the graphics
	 */
	showWin32Console();
	Window window(midEarth, 1000);

	/*
	 * run the game loop
	 */
	try 
	{
		window.go();
	} 
	catch( Ogre::Exception& e ) 
	{
		std::cout << e.getFullDescription() << std::endl;
	}

	/*
	 * bullet test
	 */
	btBroadphaseInterface* broadphase = new btDbvtBroadphase();
 
	btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
    btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
 
	btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
 
	btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
 
	dynamicsWorld->setGravity(btVector3(0,-10,0));
 
 
	btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),1);
 
	btCollisionShape* fallShape = new btSphereShape(1);
 
 
	btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,-1,0)));
	btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0));
	btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);
	dynamicsWorld->addRigidBody(groundRigidBody);
 
 
	btDefaultMotionState* fallMotionState =
		new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,50,0)));
	btScalar mass = 1;
	btVector3 fallInertia(0,0,0);
	fallShape->calculateLocalInertia(mass,fallInertia);
	btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(mass,fallMotionState,fallShape,fallInertia);
	btRigidBody* fallRigidBody = new btRigidBody(fallRigidBodyCI);
	dynamicsWorld->addRigidBody(fallRigidBody);
 
 
	for (int i=0 ; i<3000 ; i++) {
		dynamicsWorld->stepSimulation(1/60.f,10);
 
		btTransform trans;
		fallRigidBody->getMotionState()->getWorldTransform(trans);
 
		std::cout << "sphere height: " << trans.getOrigin().getY() << std::endl;
	}
 
	dynamicsWorld->removeRigidBody(fallRigidBody);

	FreeConsole();
	return 0;
}



